/*******************************************************************************
* 
* AudioSprite takes responsibility to play sounds
* 
* 
******************************************************************************/
#include "audio-sprite.h"
#include "riff-reader.h"
#include "logging.h"

using namespace noria::diagnostic;

namespace noria{ namespace xaudio
{
    AudioSprite::AudioSprite(IXAudio2* pXAudio2, cbinary_ref pcm)
        : m_voice(NULL)
    {
        LOG_INFO("AudioSprite::ctor()");
        init(pXAudio2, pcm);
    }

    AudioSprite::~AudioSprite(void)
    {
        LOG_INFO("AudioSprite::~ctor()");

        if(m_voice)
            m_voice->DestroyVoice();
    }

    void AudioSprite::init(IXAudio2* pXAudio2, cbinary_ref pcm)
    {  
        RiffReader* reader = new RiffReader();
        if(!reader->parse(pcm))
        {
            LOG_FATAL("Failure parsing PCM data.");
            return;
        }

		//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		// The following call will crash due to buffer overrun
		// Reason: unknown... 
		// Workaround: no...
		//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        HRESULT hr = pXAudio2->CreateSourceVoice(&m_voice, reader->wavefmt());
        if(FAILED(hr))
        {
            LOG_FATAL("Failure creating source voice. error=%#X", hr);
            m_voice = NULL;
            return;
        }

        XAUDIO2_BUFFER buffer = {0};
        buffer.AudioBytes = reader->size();  //buffer containing audio data
        buffer.pAudioData = reader->offset();  //size of the audio buffer in bytes
        buffer.Flags = XAUDIO2_END_OF_STREAM; // tell the source voice not to expect any data after this buffer

        hr = m_voice->SubmitSourceBuffer(&buffer);
        if(FAILED(hr))
        {
            LOG_FATAL("Failure submitting source buffer. error=%#X", hr);
            m_voice = NULL;
            return;
        }

        delete reader;
    }

    void AudioSprite::play(bool async)
    {
        if(m_voice)
        {
            m_voice->Start();

            if(!async)
            {
                bool running = true;
                while( running )
                {
                    XAUDIO2_VOICE_STATE state;
                    m_voice->GetState( &state );
                    running = ( state.BuffersQueued > 0 ) != 0;

                    Sleep( 10 );
                }
            }
        }
    }

    void AudioSprite::stop()
    {
        if(m_voice)
            m_voice->Stop();
    }

}}